home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / ofs / ofsIo.c < prev   
C/C++ Source or Header  |  1991-03-30  |  17KB  |  584 lines

  1. /* 
  2.  * ofsIo.c --
  3.  *
  4.  *    Routines providing I/O for OFS domain files.
  5.  *
  6.  * Copyright 1990 Regents of the University of California
  7.  * Permission to use, copy, modify, and distribute this
  8.  * software and its documentation for any purpose and without
  9.  * fee is hereby granted, provided that the above copyright
  10.  * notice appear in all copies.  The University of California
  11.  * makes no representations about the suitability of this
  12.  * software for any purpose.  It is provided "as is" without
  13.  * express or implied warranty.
  14.  */
  15.  
  16. #ifndef lint
  17. static char rcsid[] = "$Header: /sprite/src/kernel/ofs/RCS/ofsIo.c,v 1.3 91/03/30 17:19:36 mgbaker Exp $ SPRITE (Berkeley)";
  18. #endif /* not lint */
  19.  
  20. #include <sprite.h>
  21. #include <fs.h>
  22. #include <fsutil.h>
  23. #include <fslcl.h>
  24. #include <fsNameOps.h>
  25. #include <fsio.h>
  26. #include <fsStat.h>
  27. #include <fsdm.h>
  28. #include <fscache.h>
  29. #include <ofs.h>
  30. #include <devBlockDevice.h>
  31.  
  32. #include <stdio.h>
  33.  
  34. static Sync_Lock ofsCleanerLock = Sync_LockInitStatic("Fs:ofsCleanerLock");
  35. #define    LOCKPTR    &ofsCleanerLock
  36.  
  37. static int ofsBlockCleaners = 0; /* Number of block cleaner processes in 
  38.                   * action. */
  39.  
  40. /*
  41.  * ofsBlockWritesPerFile - maximum number of blocks written for a file
  42.  * before switching to the next dirty file.
  43.  */
  44. int    ofsBlockWritesPerFile = 25;
  45.  
  46. extern void Ofs_CleanBlocks _ARGS_((ClientData data, Proc_CallInfo *callInfoPtr));
  47. static Boolean FileMatch _ARGS_((Fscache_FileInfo *cacheInfoPtr, 
  48.                 ClientData clientData));
  49.  
  50.  
  51. /*
  52.  *----------------------------------------------------------------------
  53.  *
  54.  * Ofs_FileBlockRead --
  55.  *
  56.  *    Read in a cache block.  This does a direct disk read if the
  57.  *    file is the 'physical file' used for file descriptors and
  58.  *    indirect blocks.  If it is a regular file data block, then
  59.  *    the indexing structure is used to locate the file on disk.
  60.  *    This always attempts to read in a full block, but will read
  61.  *    less if at the last block and it isn't full.  In this case,
  62.  *    the remainder of the cache block is zero-filled.
  63.  *
  64.  * Results:
  65.  *    The results of the disk read.
  66.  *
  67.  * Side effects:
  68.  *    The buffer is filled with the number of bytes indicated by
  69.  *    the bufSize parameter.  The blockPtr->blockSize is modified to
  70.  *    reflect how much data was actually read in.  The unused part
  71.  *    of the block is filled with zeroes so that higher levels can
  72.  *    always assume the block has good stuff in all parts of it.
  73.  *
  74.  *----------------------------------------------------------------------
  75.  */
  76. /*ARGSUSED*/
  77. ReturnStatus
  78. Ofs_FileBlockRead(domainPtr, handlePtr, blockPtr)
  79.     Fsdm_Domain        *domainPtr;    /* Domain of file. */
  80.     register Fsio_FileIOHandle *handlePtr;    /* Handle on a local file. */
  81.     Fscache_Block    *blockPtr;    /* Cache block to read in.  This assumes
  82.                      * the blockNum, blockAddr (buffer area)
  83.                      * and blockSize are set.  This modifies
  84.                      * blockSize if less bytes were read
  85.                      * because of EOF. */
  86. {
  87.     register Ofs_Domain        *ofsPtr = OFS_PTR_FROM_DOMAIN(domainPtr);
  88.     register    Fsdm_FileDescriptor *descPtr;
  89.     register             offset;
  90.     register int         numBytes;
  91.     ReturnStatus         status;
  92.     OfsBlockIndexInfo         indexInfo;
  93.  
  94.     status = SUCCESS;
  95.     blockPtr->blockSize = 0;
  96.     numBytes = FS_BLOCK_SIZE;
  97.     offset = blockPtr->blockNum * FS_BLOCK_SIZE;
  98.  
  99.     if (handlePtr->hdr.fileID.minor == 0) {
  100.     /*
  101.      * If is a physical block address then read it in directly.
  102.      */
  103.     status = OfsDeviceBlockIO(ofsPtr, FS_READ, 
  104.                offset / FS_FRAGMENT_SIZE, FS_FRAGMENTS_PER_BLOCK, 
  105.                blockPtr->blockAddr);
  106.     fs_Stats.gen.physBytesRead += FS_BLOCK_SIZE;
  107.     } else {
  108.     /*
  109.      * Is a logical file read. Round the size down to the actual
  110.      * last byte in the file.
  111.      */
  112.  
  113.     descPtr = handlePtr->descPtr;
  114.     if (offset > descPtr->lastByte) {
  115.         goto exit;
  116.     } else if (offset + numBytes - 1 > descPtr->lastByte) {
  117.         numBytes = descPtr->lastByte - offset + 1;
  118.     }
  119.  
  120.     status = OfsGetFirstIndex(ofsPtr, handlePtr, offset / FS_BLOCK_SIZE, 
  121.                  &indexInfo, 0);
  122.     if (status != SUCCESS) {
  123.         printf("Ofs_FileRead: Could not setup indexing\n");
  124.         goto exit;
  125.     }
  126.  
  127.     if (indexInfo.blockAddrPtr != (int *) NIL &&
  128.         *indexInfo.blockAddrPtr != FSDM_NIL_INDEX) {
  129.         /*
  130.          * Read in the block.  Specify the device, the fragment index,
  131.          * the number of fragments, and the memory buffer.
  132.          */
  133.         status = OfsDeviceBlockIO(ofsPtr, FS_READ, 
  134.               *indexInfo.blockAddrPtr +
  135.               ofsPtr->headerPtr->dataOffset * FS_FRAGMENTS_PER_BLOCK,
  136.               (numBytes - 1) / FS_FRAGMENT_SIZE + 1,
  137.               blockPtr->blockAddr);
  138.     } else {
  139.         /*
  140.          * Zero fill the block.  We're in a 'hole' in the file.
  141.          */
  142.         fs_Stats.blockCache.readZeroFills++;
  143.         bzero(blockPtr->blockAddr, numBytes);
  144.     }
  145.     OfsEndIndex(handlePtr, &indexInfo, FALSE);
  146.     Fs_StatAdd(numBytes, fs_Stats.gen.fileBytesRead,
  147.            fs_Stats.gen.fileReadOverflow);
  148. #ifdef SOSP91
  149.     if (proc_RunningProcesses[0] != (Proc_ControlBlock *) NIL) {
  150.         if ((proc_RunningProcesses[0]->state == PROC_MIGRATED) ||
  151.             (proc_RunningProcesses[0]->genFlags &
  152.             (PROC_FOREIGN | PROC_MIGRATING))) {
  153.         Fs_StatAdd(numBytes, fs_SospMigStats.gen.fileBytesRead, 
  154.                 fs_SospMigStats.gen.fileReadOverflow);
  155.         }
  156.     }
  157. #endif SOSP91
  158.     }
  159. exit:
  160.     /*
  161.      * Define the block size and error fill leftover space.
  162.      */
  163.     if (status == SUCCESS) {
  164.     blockPtr->blockSize = numBytes;
  165.     }
  166.     if (blockPtr->blockSize < FS_BLOCK_SIZE) {
  167.     fs_Stats.blockCache.readZeroFills++;
  168.     bzero(blockPtr->blockAddr + blockPtr->blockSize,
  169.         FS_BLOCK_SIZE - blockPtr->blockSize);
  170.     }
  171.     return(status);
  172. }
  173.  
  174. /*
  175.  *----------------------------------------------------------------------
  176.  *
  177.  * Ofs_FileBlockWrite --
  178.  *
  179.  *    Write out a cache block.  This understands about physical
  180.  *    block writes as opposed to file block writes, and it understands
  181.  *    that negative block numbers are used for indirect blocks (gag).
  182.  *    Physical blocks are numbered from the beginning of the disk,
  183.  *    and they are used for file descriptors and indirect blocks.
  184.  *    File blocks are numbered from the beginning of the data block
  185.  *    area, so an offset must be used to calculate their true address.
  186.  *
  187.  * Results:
  188.  *    The return code from the driver, or FS_DOMAIN_UNAVAILABLE if
  189.  *    the domain has been un-attached.
  190.  *
  191.  * Side effects:
  192.  *    The device write.
  193.  *
  194.  *----------------------------------------------------------------------
  195.  */
  196. /*ARGSUSED*/
  197. ReturnStatus
  198. Ofs_FileBlockWrite(domainPtr, handlePtr, blockPtr)
  199.     register    Fsdm_Domain     *domainPtr;
  200.     register Fsio_FileIOHandle *handlePtr;    /* I/O handle for the file. */
  201.     Fscache_Block *blockPtr;    /* Cache block to write out. */
  202. {
  203.     register Ofs_Domain    *ofsPtr = OFS_PTR_FROM_DOMAIN(domainPtr);
  204.     ReturnStatus        status;
  205.     int                diskBlock;
  206.  
  207.     if (handlePtr->hdr.fileID.minor == 0 || blockPtr->diskBlock < 0) {
  208.     /*
  209.      * The block number is a raw block number counting from the
  210.      * beginning of the domain.
  211.      * Descriptor blocks are indicated by a handle with a 0 file number 
  212.      * and indirect a negative block number (indirect blocks).
  213.      */
  214.     if (blockPtr->diskBlock < 0) {
  215.         diskBlock = -blockPtr->diskBlock;
  216.     } else {
  217.         diskBlock = blockPtr->diskBlock;
  218.     }
  219.     fs_Stats.gen.physBytesWritten += blockPtr->blockSize;
  220.     status = OfsDeviceBlockIO(ofsPtr, FS_WRITE,
  221.              diskBlock, FS_FRAGMENTS_PER_BLOCK, blockPtr->blockAddr);
  222.     } else {
  223.     /*
  224.      * The block number is relative to the start of the data blocks.
  225.      */
  226.     status = OfsVerifyBlockWrite(ofsPtr, blockPtr);
  227.     if (status == SUCCESS) {
  228.         status = OfsDeviceBlockIO(ofsPtr, FS_WRITE,
  229.            blockPtr->diskBlock + 
  230.            ofsPtr->headerPtr->dataOffset * FS_FRAGMENTS_PER_BLOCK,
  231.            (blockPtr->blockSize - 1) / FS_FRAGMENT_SIZE + 1,
  232.            blockPtr->blockAddr);
  233.         }
  234.     if (status == SUCCESS) {
  235.         Fs_StatAdd(blockPtr->blockSize, fs_Stats.gen.fileBytesWritten,
  236.            fs_Stats.gen.fileWriteOverflow);
  237. #ifdef SOSP91
  238.         if (proc_RunningProcesses[0] != (Proc_ControlBlock *) NIL) {
  239.         if ((proc_RunningProcesses[0]->state == PROC_MIGRATED) ||
  240.             (proc_RunningProcesses[0]->genFlags &
  241.             (PROC_FOREIGN | PROC_MIGRATING))) {
  242.             Fs_StatAdd(blockPtr->blockSize,
  243.                 fs_SospMigStats.gen.fileBytesWritten, 
  244.                 fs_SospMigStats.gen.fileWriteOverflow);
  245.         }
  246.         }
  247. #endif SOSP91
  248.     }
  249.     }
  250.     return(status);
  251. }
  252.  
  253. /*
  254.  *----------------------------------------------------------------------
  255.  *
  256.  * OfsDeviceBlockIO --
  257.  *
  258.  *    Map a file system block address to a block device block address 
  259.  *    perform the requested operation.
  260.  *
  261.  * NOTE: This routine is temporary and should be replaced when the file system
  262.  *     is converted to use the async block io interface.
  263.  *
  264.  * Results:
  265.  *    The return status of the operation.
  266.  *
  267.  * Side effects:
  268.  *    Blocks may be written or read.
  269.  *
  270.  *----------------------------------------------------------------------
  271.  */
  272.  
  273. ReturnStatus
  274. OfsDeviceBlockIO(ofsPtr, readWriteFlag, fragNumber, numFrags, buffer)
  275.     Ofs_Domain    *ofsPtr;    /* Domain */
  276.     int readWriteFlag;        /* FS_READ or FS_WRITE */
  277.     int fragNumber;        /* CAREFUL, fragment index, not block index.
  278.                  * This is relative to start of device. */
  279.     int numFrags;        /* CAREFUL, number of fragments, not blocks */
  280.     Address buffer;        /* I/O buffer */
  281. {
  282.     ReturnStatus status = SUCCESS;    /* General return code */
  283.     int firstSector;        /* Starting sector of transfer */
  284.     DevBlockDeviceRequest    request;
  285.     int                transferCount;
  286.  
  287.     if ((fragNumber % FS_FRAGMENTS_PER_BLOCK) != 0) {
  288.     /*
  289.      * The I/O doesn't start on a block boundary.  Transfer the
  290.      * first few extra fragments to get things going on a block boundary.
  291.      */
  292.     register int extraFrags;
  293.  
  294.     extraFrags = FS_FRAGMENTS_PER_BLOCK -
  295.             (fragNumber % FS_FRAGMENTS_PER_BLOCK);
  296.     if (extraFrags > numFrags) {
  297.         extraFrags = numFrags;
  298.     }
  299.     firstSector = OfsBlocksToSectors(fragNumber, 
  300.             &ofsPtr->headerPtr->geometry);
  301.     request.operation = readWriteFlag;
  302.     request.startAddress = firstSector * DEV_BYTES_PER_SECTOR;
  303.     request.startAddrHigh = 0;
  304.     request.bufferLen = extraFrags * FS_FRAGMENT_SIZE;
  305.     request.buffer = buffer;
  306.     status = Dev_BlockDeviceIOSync(ofsPtr->blockDevHandlePtr, &request, 
  307.                     &transferCount);
  308.     extraFrags = transferCount / FS_FRAGMENT_SIZE;
  309.     fragNumber += extraFrags;
  310.     buffer += transferCount;
  311.     numFrags -= extraFrags;
  312.     if (status != SUCCESS) {
  313.         return(status);
  314.     }
  315.     }
  316.     while (numFrags >= FS_FRAGMENTS_PER_BLOCK) {
  317.     /*
  318.      * Transfer whole blocks.
  319.      */
  320.     firstSector = OfsBlocksToSectors(fragNumber, 
  321.             &ofsPtr->headerPtr->geometry);
  322.     request.operation = readWriteFlag;
  323.     request.startAddress = firstSector * DEV_BYTES_PER_SECTOR;
  324.     request.startAddrHigh = 0;
  325.     request.bufferLen = FS_BLOCK_SIZE;
  326.     request.buffer = buffer;
  327.     status = Dev_BlockDeviceIOSync(ofsPtr->blockDevHandlePtr, &request, 
  328.                     &transferCount);
  329.     fragNumber += FS_FRAGMENTS_PER_BLOCK;
  330.     buffer += FS_BLOCK_SIZE;
  331.     numFrags -= FS_FRAGMENTS_PER_BLOCK;
  332.     if (status != SUCCESS) {
  333.         return(status);
  334.     }
  335.     }
  336.     if (numFrags > 0) {
  337.     /*
  338.      * Transfer the left over fragments.
  339.      */
  340.     firstSector = OfsBlocksToSectors(fragNumber, 
  341.             &ofsPtr->headerPtr->geometry);
  342.     request.operation = readWriteFlag;
  343.     request.startAddress = firstSector * DEV_BYTES_PER_SECTOR;
  344.     request.startAddrHigh = 0;
  345.     request.bufferLen = numFrags * FS_FRAGMENT_SIZE;
  346.     request.buffer = buffer;
  347.     status = Dev_BlockDeviceIOSync(ofsPtr->blockDevHandlePtr, &request, 
  348.                     &transferCount);
  349.     }
  350.     return(status);
  351. }
  352.  
  353.  
  354. /*
  355.  *----------------------------------------------------------------------
  356.  *
  357.  * FsioVerifyBlockWrite --
  358.  *
  359.  *    Double check this block to make sure it seems like were writing
  360.  *    it to the right place.
  361.  *
  362.  * Results:
  363.  *    Error code if an inconsistency was detected.
  364.  *
  365.  * Side effects:
  366.  *    None.
  367.  *
  368.  *----------------------------------------------------------------------
  369.  */
  370. /*ARGSUSED*/
  371. ReturnStatus
  372. OfsVerifyBlockWrite(ofsPtr, blockPtr)
  373.     Ofs_Domain    *ofsPtr;
  374.     Fscache_Block *blockPtr;        /* Block about to be written out */
  375. {
  376.     ReturnStatus status = SUCCESS;
  377.     Fs_HandleHeader *hdrPtr = blockPtr->cacheInfoPtr->hdrPtr;
  378.     OfsBlockIndexInfo         indexInfo;
  379.  
  380.     if (blockPtr->fileNum != hdrPtr->fileID.minor) {
  381.     printf("FsioVerifyBlockWrite: block being written to wrong file\n");
  382.     printf("    Logical block %d block's file %d owning file %d \"%s\"\n",
  383.         blockPtr->blockNum, blockPtr->fileNum,
  384.         hdrPtr->fileID.minor, Fsutil_HandleName(hdrPtr));
  385.     return(FS_INVALID_ARG);
  386.     }
  387.     status = OfsGetFirstIndex(ofsPtr, (Fsio_FileIOHandle *)hdrPtr, 
  388.             blockPtr->blockNum, &indexInfo,
  389.             (int)FSCACHE_DONT_BLOCK);
  390.     if (status == FS_WOULD_BLOCK) {
  391.     /*
  392.      * No room in the cache for the index blocks needed to check.
  393.      * assume the write is ok.
  394.      */
  395.     return(SUCCESS);
  396.     } else if (status != SUCCESS) {
  397.     return(status);
  398.     }
  399.     if (indexInfo.blockAddrPtr == (int *)NIL ||
  400.     *indexInfo.blockAddrPtr == FSDM_NIL_INDEX) {
  401.     printf("FsioVerifyBlockWrite: no block index\n");
  402.     panic("    Logical block %d owning file %d \"%s\"\n",
  403.         blockPtr->blockNum, hdrPtr->fileID.minor, Fsutil_HandleName(hdrPtr));
  404.     status = FS_INVALID_ARG;
  405.     goto exit;
  406.     }
  407.     if (*indexInfo.blockAddrPtr != blockPtr->diskBlock) {
  408.     printf("OfsVerifyBlockWrite: disk block mismatch\n");
  409.     panic("    Logical block %d old disk block %d new %d owning file %d \"%s\"\n",
  410.         blockPtr->blockNum, *indexInfo.blockAddrPtr,
  411.         blockPtr->diskBlock,
  412.         hdrPtr->fileID.minor, Fsutil_HandleName(hdrPtr));
  413.     status = FS_INVALID_ARG;
  414.     goto exit;
  415.     }
  416.  
  417. exit:
  418.     OfsEndIndex((Fsio_FileIOHandle *)hdrPtr, &indexInfo, FALSE);
  419.     return(status);
  420. }
  421.  
  422. /*
  423.  * ----------------------------------------------------------------------------
  424.  *
  425.  * BlockMatch --
  426.  *
  427.  *     Cache backend block type match.  Ofs doesn't care about the 
  428.  *    order of blocks returned by GetDirtyBlocks.
  429.  *
  430.  * Results:
  431.  *    TRUE.
  432.  *
  433.  * Side effects:
  434.  *
  435.  * ----------------------------------------------------------------------------
  436.  */
  437. /*ARGSUSED*/
  438. Boolean
  439. BlockMatch(blockPtr, clientData)
  440.     Fscache_Block *blockPtr;
  441.     ClientData       clientData;
  442. {
  443.     return TRUE;
  444. }
  445.  
  446.  
  447. /*
  448.  * ----------------------------------------------------------------------------
  449.  *
  450.  * FileMatch --
  451.  *
  452.  *     Cache backend file match. Ofs will take any file the cache wants
  453.  *    it to write.
  454.  *
  455.  * Results:
  456.  *    TRUE.
  457.  *
  458.  * Side effects:
  459.  *
  460.  * ----------------------------------------------------------------------------
  461.  */
  462. /*ARGSUSED*/
  463. static Boolean
  464. FileMatch(cacheInfoPtr, clientData)
  465.     Fscache_FileInfo *cacheInfoPtr;
  466.     ClientData    clientData;
  467. {
  468.     return TRUE;
  469. }
  470.  
  471.  
  472. /*
  473.  * ----------------------------------------------------------------------------
  474.  *
  475.  * Ofs_StartWriteBack --
  476.  *
  477.  *     Start a block cleaner process for the specified domain.
  478.  *
  479.  * Results:
  480.  *    TRUE if a block cleaner was started.
  481.  *
  482.  * Side effects:
  483.  *    Number of block cleaner processes may be incremented.
  484.  *
  485.  * ----------------------------------------------------------------------------
  486.  */
  487. Boolean
  488. Ofs_StartWriteBack(backendPtr)
  489.     Fscache_Backend *backendPtr;    /* Backend to start writeback. */
  490. {
  491.     LOCK_MONITOR;
  492.     if (ofsBlockCleaners < fscache_MaxBlockCleaners) {
  493.     Proc_CallFunc(Ofs_CleanBlocks, (ClientData) backendPtr, 0);
  494.     ofsBlockCleaners++;
  495.     UNLOCK_MONITOR;
  496.     return TRUE;
  497.     }
  498.     UNLOCK_MONITOR;
  499.     return FALSE;
  500. }
  501.  
  502.  
  503. /*
  504.  * ----------------------------------------------------------------------------
  505.  *
  506.  *    Functions to clean dirty blocks.
  507.  *
  508.  * ----------------------------------------------------------------------------
  509.  */
  510.  
  511.  
  512. /*
  513.  * ----------------------------------------------------------------------------
  514.  *
  515.  * Ofs_CleanBlocks
  516.  *
  517.  *    Write all blocks on the dirty list to disk.  Called either from
  518.  *    a block cleaner process or synchronously during system shutdown.
  519.  *
  520.  * Results:
  521.  *         None.
  522.  *
  523.  * Side effects:
  524.  *         The dirty list is emptied.
  525.  *
  526.  * ----------------------------------------------------------------------------
  527.  */
  528. /*ARGSUSED*/
  529. void
  530. Ofs_CleanBlocks(data, callInfoPtr)
  531.     ClientData        data;        /* Background flag.  If TRUE it means
  532.                      * we are called from a block cleaner
  533.                      * process.  Otherwise we being called
  534.                      * synchrounously during a shutdown */
  535.     Proc_CallInfo    *callInfoPtr;    /* Not Used. */
  536. {
  537.     Fscache_Block    *blockPtr;
  538.     ReturnStatus        status;
  539.     int                lastDirtyBlock;
  540.     Fscache_FileInfo        *cacheInfoPtr;
  541.     Fscache_Backend        *backendPtr;
  542.     int                numWrites;
  543.  
  544.     backendPtr = (Fscache_Backend *) data;
  545.     cacheInfoPtr = Fscache_GetDirtyFile(backendPtr, TRUE, FileMatch, 
  546.                     (ClientData) NIL);
  547.     while (cacheInfoPtr != (Fscache_FileInfo *)NIL) {
  548.     blockPtr = Fscache_GetDirtyBlock(cacheInfoPtr, BlockMatch, 
  549.                     (ClientData) 0, &lastDirtyBlock);
  550.     numWrites = 0;
  551.     while (blockPtr != (Fscache_Block *) NIL) {
  552.         /*
  553.          * Write the block.
  554.          */
  555. #ifdef SOSP91
  556.         Fscache_AddBlockToStats(cacheInfoPtr, blockPtr);
  557. #endif SOSP91
  558.         status = Fsdm_FileBlockWrite
  559.             (cacheInfoPtr->hdrPtr, blockPtr, lastDirtyBlock);
  560.         numWrites++;
  561.         Fscache_ReturnDirtyBlock(blockPtr, status);
  562.         if (numWrites < ofsBlockWritesPerFile) {
  563.         blockPtr = Fscache_GetDirtyBlock(cacheInfoPtr, BlockMatch, 
  564.                     (ClientData) 0, &lastDirtyBlock);
  565.         } else {
  566.         break;
  567.         }
  568.     }
  569. #ifdef SOSP91
  570.     cacheInfoPtr->flags &= ~FSCACHE_REASON_FLAGS;
  571. #endif SOSP91
  572.     Fscache_ReturnDirtyFile(cacheInfoPtr, FALSE);
  573.     cacheInfoPtr = Fscache_GetDirtyFile(backendPtr, TRUE, FileMatch, 
  574.                     (ClientData) NIL);
  575.     }
  576.     FscacheBackendIdle(backendPtr);
  577.     LOCK_MONITOR;
  578.     ofsBlockCleaners--;
  579.     UNLOCK_MONITOR;
  580. }
  581.  
  582.  
  583.  
  584.